In computer programming languages, a switch statement is a type of selection control mechanism used to allow the value of a variable or expression to change the control flow of program execution via search and map.
Switch statements function somewhat similarly to the if statement used in programming languages like C/C++, C#, Visual Basic .NET, Java and exist in most high-level imperative programming languages such as Pascal, Ada, C/C++, C#, Visual Basic .NET, Java, and in many other types of language, using such keywords as switch, case, select, or inspect.
Switch statements come in two main variants: a structured switch, as in Pascal, which takes exactly one branch, and an unstructured switch, as in C, which functions as a type of goto. The main reasons for using a switch include improving clarity, by reducing otherwise repetitive coding, and (if the permit) also offering the potential for faster execution through easier compiler optimization in many cases.
+ An example of a switch statement in C | case 1: printf("You're one."); break; case 2: printf("You're two."); break; case 3: printf("You're three."); case 4: printf("You're three or four."); break; default: printf("You're not 1, 2, 3 or 4!");} |
Kleene provides a proof of this in terms of the Boolean-like recursive functions "sign-of" sg( ) and "not sign of" ~sg( ) (Kleene 1952:222-223); the first returns 1 if its input is positive and −1 if its input is negative.
Boolos-Burgess-Jeffrey make the additional observation that "definition by cases" must be both mutually exclusive and collectively exhaustive. They too offer a proof of the primitive recursiveness of this function (Boolos-Burgess-Jeffrey 2002:74-75).
The IF-THEN-ELSE is the basis of the McCarthy formalism: its usage replaces both primitive recursion and the mu-operator.
The earliest Fortran compilers supported the computed GOTO statement for multi-way branching. Early ALGOL compilers supported a SWITCH data type which contains a list of "designational expressions". A GOTO statement could reference a switch variable and, by providing an index, branch to the desired destination. With experience it was realized that a more formal multi-way construct, with single point of entrance and exit, was needed. Languages such as BCPL, ALGOL-W, and ALGOL-68 introduced forms of this construct which have survived through modern languages.
Each alternative begins with the particular value, or list of values (see below), that the control variable may match and which will cause the control to goto the corresponding sequence of statements. The value (or list/range of values) is usually separated from the corresponding statement sequence by a colon or by an implication arrow. In many languages, every case must also be preceded by a keyword such as case or when.
An optional default case is typically also allowed, specified by a default, otherwise, or else keyword. This executes when none of the other cases match the control expression. In some languages, such as C, if no case matches and the default is omitted the switch statement simply does nothing. In others, like PL/I, an error is raised.
The first form are structured switches, as in Pascal, where exactly one branch is taken, and the cases are treated as separate, exclusive blocks. This functions as a generalized if–then–else conditional, here with any number of branches, not just two.
The second form are unstructured switches, as in C, where the cases are treated as labels within a single block, and the switch functions as a generalized goto. This distinction is referred to as the treatment of fallthrough, which is elaborated below.
Languages derived from C language, and more generally those influenced by Fortran's computed GOTO, instead feature fallthrough, where control moves to the matching case, and then execution continues ("falls through") to the statements associated with the next case in the source text. This also allows multiple values to match the same point without any special syntax: they are just listed with empty bodies. Values can be special conditioned with code in the case body. In practice, fallthrough is usually prevented with a break keyword at the end of the matching body, which exits execution of the switch block, but this can cause bugs due to unintentional fallthrough if the programmer forgets to insert the break statement. This is thus seen by manyvan der Linden, Peter (1994). Expert C Programming: Deep C Secrets, p. 38. Prentice Hall, Eaglewood Cliffs. . as a language wart, and warned against in some . Syntactically, the cases are interpreted as labels, not blocks, and the switch and break statements explicitly change control flow. Some languages influenced by C, such as JavaScript, retain default fallthrough, while others remove fallthrough, or only allow it in special circumstances. Notable variations on this in the C-family include C#, in which all blocks must be terminated with a break or return unless the block is empty (i.e. fallthrough is used as a way to specify multiple values).
In some cases languages provide optional fallthrough. For example, Perl does not fall through by default, but a case may explicitly do so using a continue keyword. This prevents unintentional fallthrough but allows it when desired. Similarly, Bash defaults to not falling through when terminated with ;;, but allows fallthroughsince version 4.0, released in 2009. with ;& or ;;& instead.
An example of a switch statement that relies on fallthrough is Duff's device.
Normally, the only method of finding out if this optimization has occurred is by actually looking at the resultant assembly or machine code output that has been generated by the compiler.
Additionally, an optimized implementation may execute much faster than the alternative, because it is often implemented by using an indexed branch table.
In terms of the control-flow graph, a switch statement consists of two nodes (entrance and exit), plus one edge between them for each option. By contrast, a sequence of "if...else if...else if" statements has an additional node for every case other than the first and last, together with a corresponding edge. The resulting control-flow graph for the sequences of "if"s thus has many more nodes and almost twice as many edges, with these not adding any useful information. However, the simple branches in the if statements are individually conceptually easier than the complex branch of a switch statement. In terms of cyclomatic complexity, both of these options increase it by k−1 if given k cases.
case JAN, MAR, MAY, JUL, AUG, OCT, DEC -> 31; case APR, JUN, SEP, NOV -> 30; case FEB -> { if (year % 400 == 0) yield 29; else if (year % 100 == 0) yield 28; else if (year % 4 == 0) yield 29; else yield 28; }};
case ($x == 'hello'): foo(); break; case ($z == 'howdy'): break;} switch (5) {
case $x: break; case $y: break;}
This feature is also useful for checking multiple variables against one value rather than one variable against many values. COBOL also supports this form (and other forms) in the EVALUATE statement. PL/I has an alternative form of the SELECT statement where the control expression is omitted altogether and the first WHEN that evaluates to true is executed.
Ruby also returns a value that can be assigned to a variable, and doesn’t actually require the case to have any parameters (acting a bit like an else if statement):
case
when cat.age <= 1
junior
when cat.age > 10
senior
else
normal
end
cmp ah, 00h je a cmp ah, 01h je b jmp swtend ; No cases match or "default" code herea:
push ah mov al, 'a' mov ah, 0Eh mov bh, 00h int 10h pop ah jmp swtend ; Equivalent to "break"b:
push ah mov al, 'b' mov ah, 0Eh mov bh, 00h int 10h pop ah jmp swtend ; Equivalent to "break" ...swtend:
case "a" | "e" | "i" | "o" | "u": # Unlike conditions in if statements, the `or` keyword cannot be used here to differentiate between cases print(f"Letter {letter} is a vowel!") case "y": print(f"Letter {letter} may be a vowel.") case _: # `case _` is equivalent to `default` from C and others print(f"Letter {letter} is not a vowel!")
|
|